home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / ARCETHER.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  35KB  |  1,083 lines

  1. ;History:896,1
  2. ;Sun Jan 05 22:13:57 1992 increased RST_IVAL from 4 to 7.
  3. ;Tue Feb 27 10:56:15 1990 send_pkt wasn't timing out properly.
  4. version    equ    0
  5.  
  6.     include    defs.asm
  7.  
  8. ;Ported from Philip Prindeville's arcnet driver for PCIP
  9. ;by Russell Nelson.  Any bugs are due to Russell Nelson.
  10.  
  11. ;Ported from Philip Prindevilles's and Russell Nelson's ARCNET
  12. ;driver to RFC1201 and class Ethernet by Martin Wilmes (Q91@DHDURZ1.BITNET).
  13. ;So any bugs are now due to Martin Wilmes.
  14.  
  15. ;  Parts Copyright, 1988-1992, Russell Nelson, Crynwr Software
  16. ;  Copyright 1991 Martin Wilmes
  17.  
  18. ;   This program is free software; you can redistribute it and/or modify
  19. ;   it under the terms of the GNU General Public License as published by
  20. ;   the Free Software Foundation, version 1.
  21. ;
  22. ;   This program is distributed in the hope that it will be useful,
  23. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25. ;   GNU General Public License for more details.
  26. ;
  27. ;   You should have received a copy of the GNU General Public License
  28. ;   along with this program; if not, write to the Free Software
  29. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  30.  
  31. code    segment    word public
  32.     assume    cs:code, ds:code
  33.  
  34. ;Registers:
  35.  
  36. ;the following I/O addresses are mapped to the COM 9026
  37. IMASK        equ    0        ; writeable
  38. STATUS        equ    0        ; readable
  39. COMMAND        equ    1
  40. ;the following I/O addresses are mapped to the 8253 counter/timer
  41. CNTR0        equ    4
  42. CNTR1        equ    5
  43. CNTR2        equ    6
  44. MODE        equ    7
  45. ;reading the following I/O addresse performs a software reset.
  46. SW_RST        equ    8
  47.  
  48. ; time needed to do various things (in clock ticks)
  49. RST_IVAL    equ    7        ;reset
  50. SEND_IVAL    equ    4        ;send
  51. ACK_IVAL        equ     4               ;acknowledge
  52.  
  53. ; Maximum number of replays of an unacknowledged packet
  54. SEND_REPLAY     equ     5               ;times a packet should be replayed
  55.                                         ;when we get no acknowledge, not
  56.                                         ;yet used
  57.  
  58. ; ARP type for ARCnet
  59. ARP_ARC        equ    001h           ; We are ARCnet but show up as EtherNet
  60.  
  61. ; broadcast address is nid 0
  62. ARC_BCAST    equ    0              ;ARCnet Broadcast address
  63.  
  64. ; packet sizes
  65. ARC_MTU        equ    249            ;These are the length of client data!
  66. ARC_MnTU    equ    252            ;
  67. ARC_XMTU    equ    504            ;
  68. ;
  69. ;status/interrupt mask bit fields
  70. ;
  71. ST_TA        equ    001h        ; transmitter available
  72. ST_TMA        equ    002h        ; transmitted msg. ackd
  73. ST_RECON    equ    004h        ; system reconfigured
  74. ST_TEST        equ    008h        ; test flag
  75. ST_POR        equ    010h        ; power-on-reset
  76. ST_ETS1        equ    020h        ; unused
  77. ST_ETS2        equ    040h        ; unused
  78. ST_RI        equ    080h        ; receiver inhibited
  79.  
  80. ;
  81. ;in the command register, the following bits have these meanings:
  82. ;        0-2    command
  83. ;        3-4    page number (enable rvc/xmt)
  84. ;         7    rcv b'casts
  85.  
  86.  
  87. DSBL_XMT    equ    001h        ; disable transmitter
  88. DSBL_RCV    equ    002h        ; disable receiver
  89. ENBL_XMT    equ    003h        ; enable transmitter
  90. ENBL_RCV    equ    004h        ; enable receiver
  91. DFN_CONF    equ    005h        ; define configuration
  92. CLR_FLGS    equ    006h        ; clear flags
  93. LD_TST_FLG    equ    007h        ; load test flags
  94.  
  95. ; flags for clear flags operation
  96.  
  97. FL_POR        equ    008h        ; power-on-reset
  98. FL_RECON    equ    010h        ; system reconfigured
  99.  
  100. ; flags for load test flags operation
  101.  
  102. FL_TST        equ    008h        ; test flag (diagnostic)
  103.  
  104. ; byte deposited into first address of buffers when POR
  105. TSTWRD        equ    0321Q
  106.  
  107. ; handy macros for enable receiver/transmitter
  108.  
  109. BCAST        equ    080h        ; receiver only
  110.  
  111. ; flags for define configuration
  112.  
  113. CONF_NORM    equ    000h        ; 1-249 byte packets
  114. CONF_XTND    equ    008h        ; 250-504 byte packets
  115.  
  116.  
  117.          public    no_confident
  118. NO_CONFIDENT    db      1
  119.  
  120. ; designations for receiver/transmitter buffers.  sorry, no cleverness here
  121. RCVPAGE        equ    0
  122. XMTPAGE        equ    3
  123.  
  124. my_arcnet_id    db    0            ;my arcnet ID.
  125.  
  126. ; Flag which indicates that we should build and expect 802.3 framed Novell
  127. ; IPX packets from the IPX-Shell, set to N_OPTION in this case
  128. OPTION_8023     db      0
  129.  
  130. ; Maximum number of fragments we can store in our receive-buffer
  131. MAX_FRAGMENTS   equ     3
  132.  
  133. ; Data for sending splitted packets
  134.  
  135. send_did        db      0                   ;Destination ID
  136. send_sid        db      0                   ;Source ID
  137. Stored_CX       dw      0                   ;Rest of packet not send yet
  138. Protocol_ID     db      0                   ;The ARCnet protocol ID
  139. Split_Number    db      0                   ;Number of fragments we have to send
  140. Pkt_Number      db      0                   ;Number of the current packet
  141. Sequence_Number dw      0                   ;Sequence number, start with zero
  142. send_times      db      0                   ;times a packet has been replayed
  143.  
  144. ; Data for receiving splitted packets
  145.  
  146. last_expected      db      0feh             ;Splitflag of last Packet in a
  147.                                             ;sequence - 1
  148. expected_packet    db      0                ;Used to test a sequence
  149. expected_sequence  dw      0
  150. recv_protocol      dw      0                ;Ethernet protocol
  151. recv_num_frags     db      0                ;Number of fragments we received
  152. recv_protocolbyte  db      0                ;ARCnet protocol
  153. recv_offset        dw      0
  154. recv_packet        dw      0
  155. last_length        dw      0
  156.  
  157. ; We store all but the last fragments of incomplete sequences in our own
  158. ; buffer. This is not necessary since the ARCnet card has 4 pages and we
  159. ; should receive a maximum of 3 fragments in a sequence. Using our own
  160. ; buffer has two advantages: Our driver becomes faster because it uses
  161. ; idle times when the packet not complete to test the sequence and
  162. ; reassemble the client data and our own buffer makes it easier to
  163. ; change the driver to receive more than 3 fragments if required.
  164. recv_buffer        db      (MAX_FRAGMENTS-1)*504 dup (0feh)
  165.  
  166.     public    int_no
  167. int_no        db    5,0,0,0        ; interrupt number.
  168. io_addr        dw    02e0h,0        ; I/O address for card (jumpers)
  169. mem_base    dw    0d800h,0
  170.  
  171.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  172. driver_class    db    1,0,0           ;We show as Ethernet driver, class 1.
  173.                                         ;when the OPTION_8023 flag is set, we
  174.                                         ;don not refuse calls for a class 11
  175.                                         ;driver since the PDIPX-shell asks for
  176.                                         ;a class 11 driver
  177. driver_type    db    14           ;Datapoint RIM (from the packet spec)
  178. driver_name    db    'ARCEther',0    ;name of the driver.
  179. driver_function    db    2
  180. parameter_list    label    byte
  181.     db    1    ;major rev of packet driver
  182.     db    0    ;minor rev of packet driver
  183.     db    14    ;length of parameter list
  184.     db    6    ;length of MAC-layer address
  185.     dw    1514    ;MTU, including MAC headers
  186.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  187.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  188.     dw    0    ;(# of successive xmits) - 1
  189. int_num    dw    0    ;Interrupt # to hook for post-EOI
  190.             ;processing, 0 == none,
  191.  
  192.     public    rcv_modes
  193. rcv_modes    dw    4        ;number of receive modes in our table.
  194.         dw    0,0,0,rcv_mode_3
  195.  
  196.     include    movemem.asm
  197.  
  198.     public    as_send_pkt
  199. ; The Asynchronous Transmit Packet routine.
  200. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  201. ;   interrupts possibly enabled.
  202. ; Exit with nc if ok, or else cy if error, dh set to error number.
  203. ;   es:di and interrupt enable flag preserved on exit.
  204. as_send_pkt:
  205.     ret
  206.  
  207.     public    drop_pkt
  208. ; Drop a packet from the queue.
  209. ; Enter with es:di -> iocb.
  210. drop_pkt:
  211.     assume    ds:nothing
  212.     ret
  213.  
  214.     public    xmit
  215. ; Process a transmit interrupt with the least possible latency to achieve
  216. ;   back-to-back packet transmissions.
  217. ; May only use ax and dx.
  218. xmit:
  219.     assume    ds:nothing
  220.     ret
  221.  
  222.  
  223.     public    send_pkt
  224. send_pkt:
  225. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  226. ;  (only if the high-performance bit is set in driver_function)
  227. ;enter with ds:si -> packet, cx = packet length.
  228. ;exit with nc if ok, or else cy if error, dh set to error number.
  229.     assume    ds:nothing
  230.  
  231.         push    ds
  232.         push    si
  233.         push    cx
  234.  
  235.         mov     send_did,0              ;Assume that destination is broadcast
  236.         mov     cx,3
  237.         mov     ax,ds:[si+4]
  238.         cmp     ax,0ffffh               ;A first fast check for non-Broadcast
  239.         jne     send_non_broadcast
  240. send_adress_loop:
  241.         lodsw
  242.         cmp     ax,0ffffh
  243.         jne     send_after_loop
  244.         loop    send_adress_loop
  245.         jmp     nr_3                    ;destination is indeed broadcast
  246. send_after_loop:
  247.         dec     cx                      ;read the rest of the ethernet adress
  248.         rep     lodsw
  249. send_non_broadcast:
  250.         mov     cs:send_did,ah          ;arcnet address is highest byte of
  251.                                         ;the ethernet address
  252. nr_3:
  253.         pop     cx
  254.         pop     di
  255.         pop     es                     ;We change ds:si to to es:di because we
  256.                                        ;we want to access our own data more easily.
  257.         mov     ax,cs
  258.         mov     ds,ax
  259.         assume  ds:code
  260.  
  261.         mov     ax,es:[di+10]          ;source ID
  262.         mov     send_sid,ah
  263.         mov     ax,es:[di+12]          ;Ethernet Protocol
  264.         cmp     ax,0008h               ;IP Packet
  265.         jne     nr_5
  266.         mov     protocol_ID,212        ;IP on ARCnet
  267.         jmp     nr_10
  268. nr_5:
  269.         cmp     ax,0608h               ;ARP packet
  270.         jne     nr_6
  271.         mov     protocol_ID,213        ;ARP on ARCnet
  272.         mov     cx,18+14               ;18Bytes is ARP and RARP on Arcnet
  273.                                        ;14 Byte for EtherNet Header and Protocol
  274.                                        ;which we forget later
  275.         jmp     nr_10
  276. nr_6:
  277.         cmp     ax,3580h               ;RARP packet
  278.         jne     nr_7
  279.         mov     protocol_ID,214        ;RARP on ARCnet
  280.         mov     cx,18+14
  281.         jmp     nr_10
  282. nr_7:
  283.         test    OPTION_8023,N_OPTION   ;do we expect 802.3 packets?
  284.         jnz     nr_7a
  285.         cmp     ax,3781h               ;No: check for Bluebox IPX protocol
  286.         jne     nr_error
  287.         mov     protocol_id,250        ;IPX on ARCnet
  288.         jmp     nr_10
  289. nr_7a:
  290.         mov     ax,es:[di+14]          ;Every IPX packet begins with ffff.
  291.         cmp     ax,0ffffh              ;so we check the begin of the client
  292.                                        ;data for this signature
  293.         jne     nr_error
  294.         mov     protocol_ID,250
  295.         jmp     nr_10
  296.  
  297. nr_error:                              ;We do not now this protocol and
  298.         assume  ds:nothing             ;cannot send
  299.         mov     dh,CANT_SEND
  300.         stc
  301.         ret
  302.  
  303. nr_10:
  304.         sub     cx,14                  ;Forget EtherNet-Header
  305.         add     di,14
  306.         inc     sequence_number
  307.         ;
  308.         ;Look if we can send it as one packet or have to split the packet
  309.         ;
  310.         xor     al,al
  311.         mov     Split_Number,0          ;Number of splits is zero in case of one packet
  312.         mov     pkt_number,0            ;Fragment number is zero for the first packet
  313.     cmp    cx,ARC_XMTU        ;length of client data longer than long frame?
  314.     jbe    new_send            ;no, we can send it as one packet
  315.         mov     split_number,1          ;division takes so long, so we just
  316.         cmp     cx,1008                 ;compare
  317.         jbe     new_send
  318.         mov     split_number,3
  319.         ;
  320. ;Wait for transmitter ready.
  321.         ;
  322. New_send:
  323.         push    es                      ;save current position of paket
  324.         push    di
  325. New_send_2:
  326.     loadport
  327.     setport    STATUS
  328.  
  329.     mov    ax,SEND_IVAL        ;only wait this long for it.
  330.     call    set_timeout        ;otherwise we can't send.
  331. send_pkt_3:
  332.     in    al,dx            ;if not busy, exit.
  333.     and    al,ST_TA
  334.     jne    send_pkt_2
  335.     call    do_timeout        ;did we time out yet?
  336.     jne    send_pkt_3        ;no, not yet.
  337.  
  338.         loadport
  339.     setport    COMMAND            ;stop the transmit.
  340.     mov    al,DSBL_XMT
  341.     out    dx,al
  342.     mov    dh,CANT_SEND        ;timed out, can't send.
  343.         pop     si
  344.         pop     ds
  345.         assume  ds:nothing
  346.         stc
  347.     ret
  348.  
  349. send_pkt_2:
  350. ;store the packet on the board.
  351.     mov    es,mem_base
  352.     mov    di,XMTPAGE * 512
  353.  
  354.         mov     al,send_sid
  355.         mov     ah,send_did
  356.     stosw                ;move the SID and DID to the board.
  357.         mov     Stored_CX,cx            ;remeber the packet length
  358.  
  359.         cmp     cx,ARC_MTU              ;Decide which frame we use
  360.         jbe     Send_normal_1           ;normal frame
  361.         cmp     cx,ARC_MNTU
  362.         jbe     send_pkt_5a             ;exceptional frame
  363.         ;                               ;build header for long frame
  364.         xor    ax,ax
  365.         cmp    cx,ARC_XMTU              ;length less than long Frame ?
  366.         jbe    send_Long_1              ;yes, send it
  367.         mov    cx,ARC_XMTU              ;No: send 504 bytes
  368. send_Long_1:
  369.         mov    ax,508                   ;number of bytes - 4 Byte header
  370.         sub    ax,cx                    ;Offset is 508 - clientData
  371.         mov    ah,al                    ;length in ah for stosw and long frame
  372.         xor    al,al                    ;al=0 indicates non-normal frame
  373.         stosw                           ;
  374.         mov     al,ah                   ;Move offset to back to al
  375.         xor     ah,ah                   ;
  376.         sub     al,4                    ; -4 Byte for long frame
  377.         add     di,ax                   ;jump over unused bytes
  378.         jmp     send_splits
  379. send_pkt_5a:                            ; build header for exceptional frame
  380.         ;
  381.         mov     ax,504                  ;Octet-Zahl - 8 Byte (long frame - 4 padding bytes)
  382.         sub     ax,cx                   ;Offset is 504 - clientData
  383.         mov     ah,al                   ;
  384.         xor     al,al                   ;
  385.         stosw                           ;
  386.         mov     al,ah                   ;
  387.         xor     ah,ah                   ;
  388.         sub     al,4                    ;
  389.         add     di,ax                   ;
  390.         mov     al,Protocol_ID          ;First padding byte
  391.         mov     ah,0ffh                 ;indicates exceptional frame
  392.         stosw                           ;
  393.         mov     ax,0ffffh               ;Another two padding bytes
  394.         stosw                           ;
  395.         jmp     send_splits
  396.  
  397.         ;                               header for normal frame
  398. send_normal_1:
  399.         mov     ax,252                  ;
  400.         sub     ax,cx                   ;Offset is 252 - clientData
  401.         xor     ah,ah
  402.         stosb                           ;store offset
  403.         sub     al,3                    ;
  404.         add     di,ax                   ;jump over unused bytes
  405.  
  406. Send_Splits:
  407.         mov    al,Protocol_ID
  408.         xor    ah,ah                    ;We hope it was only one packet
  409.         cmp    Split_number,0
  410.         je     Send_Transmit_split      ;Ok, it was only one
  411.         cmp    Pkt_number,0             ;A sequence: is it the first fragment
  412.         jne    Send_Splits_2            ;
  413.         mov    ah,Split_Number          ;yes: Splitflag is (T-2)*2+1
  414.         jmp    send_Transmit_split      ;and send it
  415. Send_Splits_2:
  416.         mov    ah,Pkt_number            ;
  417.  
  418. Send_Transmit_split:
  419.         stosw                           ;
  420.         mov    ax,Sequence_Number       ;
  421.         stosw
  422.         cmp    protocol_ID,213          ;ARP and RARP packets differ between
  423.         je     send_arp                 ;ARCnet and Ethernet, because the hardware
  424.         cmp    protocol_ID,214          ;type is 7 for ARCnet and 1 for Ethernet and
  425.         je     send_ARP                 ;address length are 1 for ARCnet and 6 for Ethernet
  426.         cld
  427.         pop    si                       ;its and IP or IPX packet: just send it
  428.         pop    ds                       ;ds:si for movsw
  429.         assume ds:nothing
  430.         push   cx
  431.         call   movemem                  ;und nun noch cx bytes clientdata übertragen   ****
  432.         pop    cx
  433.         push   ds                       ;the next fragment
  434.         push   si
  435.         mov    ax,cs
  436.         mov    ds,ax
  437.         assume ds:code
  438.         jmp    send_transmit
  439. Send_ARP:
  440.         pop    si
  441.         pop    ds
  442.         assume ds:nothing
  443.         mov    ax,0700h                 ;HardwareType ARCnet
  444.         stosw
  445.         mov    ax,0008h                 ;Protocol is IP
  446.         stosw
  447.         mov    ax,0401h                 ;Hardware and IP-Length
  448.         stosw
  449.         add    si,6
  450.         movsw                           ;move opcode
  451.         add    si,5
  452.         movsb                           ;sender hardware adress
  453.         movsw                           ;sender IP Adress
  454.         movsw
  455.         push   cx
  456.         mov    cx,3
  457. Send_ARP_loop:                          ;check ARP destination for broadcast
  458.         lodsw
  459.         cmp    ax,0ffffh
  460.         je     Send_ARP_1
  461.         loop   Send_ARP_loop
  462.         xor    al,al
  463.         jmp    Send_ARP_2
  464. send_ARP_1:
  465.         dec    cx
  466.         rep    lodsw
  467.         mov    al,ah
  468. send_ARP_2:
  469.         stosb
  470.  
  471.         movsw                   ;destination IP address
  472.         movsw
  473.         pop    cx               ;cx was on the stack
  474.         push   ds
  475.         push   si
  476.         mov    ax,cs
  477.         mov    ds,ax
  478.         assume ds:code
  479. send_transmit:                  ;now send the packet
  480.  
  481.     mov    al,ENBL_XMT or (XMTPAGE shl 3)
  482.     loadport
  483.     setport    COMMAND
  484.     out    dx,al
  485.         mov     al,pkt_number
  486.         cmp     al,split_number                   ;was it the last fragment
  487.         jae     send_ende                         ;yes: sending is done
  488.         add     pkt_number,2
  489.         mov     cx,Stored_CX
  490.         sub     cx,ARC_XMTU                       ;No: we did send a long packet
  491.         jmp     New_Send_2
  492. send_ende:
  493.         pop     si
  494.         pop     ds
  495.         assume  ds:nothing
  496.     clc
  497.     ret
  498.  
  499.     public    get_address
  500. get_address:
  501. ;get the address of the interface.
  502. ;enter with es:di -> place to get the address, cx = size of address buffer.
  503. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  504.     assume    ds:code
  505.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  506.     mov    dh,NO_SPACE
  507.     jb    get_address_2
  508.  
  509.         mov     cx,EADDR_LEN-1
  510.         xor     al,al                   ;fill first five bytes of Ethernet
  511.         rep     stosb                   ;address with zero
  512.     mov    al,my_arcnet_id        ;store our ARCnet address in last byte
  513.     stosb                           ;of Ethernet address
  514.  
  515.     mov    cx,EADDR_LEN
  516.     clc
  517.     ret
  518. get_address_2:
  519.     stc
  520.     ret
  521.  
  522.  
  523. ;Set address on controller
  524.     public    set_address
  525. set_address:
  526.     assume    ds:nothing
  527. ;enter with ds:si -> address, CX = length of address.
  528. ;exit with nc if okay, or cy, dh=error if any errors.
  529.     mov    dh,CANT_SET
  530.     stc
  531.     ret
  532.  
  533.  
  534. rcv_mode_3:
  535. ;receive mode 3 is the only one we support, so we don't have to do anything.
  536.     ret
  537.  
  538.  
  539.     public    set_multicast_list
  540. set_multicast_list:
  541. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  542. ;return nc if we set all of them, or cy,dh=error if we didn't.
  543.     mov    dh,NO_MULTICAST
  544.     stc
  545.     ret
  546.  
  547.  
  548.     public    terminate
  549. terminate:
  550.     assume    ds:code
  551.     loadport
  552.     setport    IMASK
  553.     mov    al,0
  554.     out    dx,al
  555.  
  556.         loadport
  557.     setport COMMAND
  558.     mov    al,DSBL_RCV
  559.     out    dx,al
  560.     mov    al,DSBL_XMT
  561.     out    dx,al
  562.  
  563.         loadport
  564.     setport    STATUS            ;do we need to do this [rnn]?
  565.     in    al,dx
  566.  
  567.     ret
  568.  
  569.  
  570.     public    reset_interface
  571. reset_interface:
  572. ;reset the interface.
  573. ;we don't do anything.
  574.     ret
  575.  
  576.  
  577.     include    timeout.asm
  578.  
  579. ;called when we want to determine what to do with a received packet.
  580. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  581.     extrn    recv_find: near
  582.  
  583. ;called after we have copied the packet into the buffer.
  584. ;enter with ds:si ->the packet, cx = length of the packet.
  585.     extrn    recv_copy: near
  586.  
  587.     extrn    count_in_err: near
  588.     extrn    count_out_err: near
  589.  
  590.     public    recv
  591. recv:
  592. ;called from the recv isr.  All registers have been saved, and ds=cs.
  593. ;Upon exit, the interrupt will be acknowledged.
  594.     assume    ds:code
  595.  
  596. recv_1:
  597.         loadport            ;get the status to see if we got
  598.     setport    STATUS            ;a false alarm.
  599.     in    al,dx
  600.         test    al,ST_RI
  601.         jnz     recv_1a                 ;its a packet, don't exit
  602.         ret
  603. recv_1a:
  604.         mov     es,mem_base             ;access the card via es:bx
  605.     mov    bx,RCVPAGE * 512
  606.  
  607. ;get packet length and splitflag
  608.         mov     ax,es:[bx+2]            ;look for offset
  609.         mov     cx,252                  ;-4 for client data
  610.         cmp     al,0                    ;test for non-normal frame
  611.         jne     short recv_my_1
  612.         mov     cx,508
  613.         mov     al,ah
  614. recv_my_1:
  615.         xor     ah,ah
  616.         add     bx,ax                 ;jump to packet
  617.         sub     cx,ax
  618.         mov     ax,es:[bx]
  619.         cmp     ah,0ffh               ;test for exceptional frame
  620.         jne     short recv_my_2
  621.         add     bx,4
  622.         sub     cx,4
  623.         mov     ax,es:[bx]            ;get the real splitflag
  624. recv_my_2:
  625.         test    ah,1
  626.         jz      recv_more             ;with the first fragment of a packet we
  627.                                       ;must be very fast because Novell
  628.                                       ;transmits fast, so we don't jump
  629.         cmp     ah,(MAX_FRAGMENTS - 2)*2+1
  630.         ja      recv_reset
  631. recv_new:
  632.         mov     last_expected,ah      ;in a new sequence the splitflag is
  633.                                       ;last splitflag -1 or zero for one packet
  634.         mov     recv_protocolbyte,al  ;protocol for tests
  635.         mov     di,es:[bx+2]
  636.         mov     expected_sequence,di
  637.         mov     recv_offset,offset recv_buffer
  638.         xor     ah,ah                 ;zero it because otherwise we would
  639.                                       ;think the sequence is complete with the
  640.                                       ;first packet
  641. recv_my_5:
  642.         cmp    ah,last_expected       ;was it the last fragment?
  643.         jae    recv_to_application    ;Never store the last fragment
  644.         push   ax
  645.         mov    ds,mem_base            ;move packet to the buffer
  646.         assume ds:nothing
  647.         mov    si,bx
  648.         add    si,4
  649.         mov    bx,cs
  650.         mov    es,bx
  651.         mov    di,cs:recv_offset
  652.  
  653.         cld
  654.         call   movemem
  655.         mov    ax,cs
  656.         mov    ds,ax
  657.         assume ds:code
  658.         pop    ax
  659.         mov    recv_offset,di
  660.         mov    expected_packet,ah
  661.         add    expected_packet,2        ;the next packet to expect
  662. recv_isr_9:
  663.  
  664.     loadport            ;enable reception again.
  665.     setport    COMMAND
  666.     mov    al,ENBL_RCV or (RCVPAGE shl 3) or BCAST
  667.     out    dx,al
  668.  
  669.     jmp    recv_1
  670. recv_reset:
  671.         mov     last_expected,0feh      ;If a in-sequenve packet tests not ok
  672.         jmp     recv_isr_9
  673.  
  674. recv_more:
  675.         cmp     ah,0
  676.         je      recv_new                 ;splitflag zero is a new packet
  677.         cmp     last_expected,0feh       ;Are we in a sequence?
  678.         je      recv_isr_9               ;No
  679.         cmp     ah,expected_packet       ;Test splitflag,protocolbyte and sequence number
  680.         jb      recv_isr_9               ;Its a replayed (or wrong) packet
  681.         ja      recv_reset               ;Packet out of order
  682.         cmp     recv_protocolbyte,al
  683.         jne     recv_reset
  684.         mov     di,es:[bx+2]
  685.         cmp     di,expected_sequence
  686.         jne     recv_reset
  687.         cmp     ah,(MAX_FRAGMENTS - 1)*2    ;we can only store MAX_FRAGMENT
  688.         jbe     recv_My_5
  689.         jmp     recv_reset
  690.  
  691. recv_to_application:                          ;we gathered the whole sequence
  692.                                               ;and have now (hopefully) enough
  693.                                               ;time to build the EtherNet Packet
  694.         add     bx,4
  695.         mov     recv_packet,bx                ;offset of client data for the last fragment
  696.         mov     last_length,cx                ;length of client data of the last fragment
  697.         mov     ax,ds
  698.         mov     es,ax
  699.         mov     cx,recv_offset
  700.         sub     cx,offset recv_buffer         ;length of reassembled part
  701.  
  702.         mov     last_expected,0feh            ;the sequence is complete
  703.         add     cx,14                         ;for the EtherNet-Header
  704.         add     cx,last_length                ;and the last fragment
  705.  
  706.         mov     al,recv_protocolbyte
  707.         mov     dl,driver_class
  708.         cmp     al,250                  ;is it IPX
  709.         jne     recv_new_4              ;No
  710.         mov     recv_protocol,3781h
  711.         test    OPTION_8023,N_OPTION    ;Is 802.3-Option set ?
  712.         jz      recv_new_10             ;No, proceed as normal
  713.         mov     dl,11                   ;Yes, now we are driver class 11
  714.         mov     recv_protocol,0ffffh    ;and use novell protocol ffffh
  715.         jmp     recv_new_10
  716.  
  717. recv_isr_9a:
  718.         jmp     recv_isr_9
  719.  
  720. recv_new_4:
  721.         cmp     al,212
  722.         jne     recv_new_5
  723.         mov     recv_protocol,0008h     ;IP packet
  724.         jmp     recv_new_10
  725. recv_new_5:
  726.         cmp     al,213
  727.         jne     recv_new_6
  728.         mov     recv_protocol,0608h     ;ARP Packet
  729.         mov     cx,42
  730.         jmp     recv_new_10
  731. recv_new_6:
  732.         cmp     al,214
  733.         jne     recv_new_7
  734.         mov     recv_protocol,3580h     ;RARP Packet
  735.         mov     cx,42
  736.         jmp     recv_new_10
  737.  
  738. recv_new_7:
  739.         ;mov     ah,al
  740.         ;mov     recv_protocol,ax        ;We dont know the frame and
  741.                                          ;double te protocol ID for inspection of
  742.                                          ;these packets by a watch client
  743.         jmp      recv_isr_9              ;to be comaptible with other drivers,
  744.                                          ;we just free the frame
  745. recv_new_10:
  746.         push    cx
  747.         mov     ax,ds
  748.         mov     es,ax
  749.         mov     di,offset recv_protocol
  750.         call    recv_find                ;find a client who wants this packet
  751.         pop     cx
  752.  
  753.         mov     ax,es                        ;is this pointer null?
  754.         or      ax,di
  755.  
  756.         je      recv_isr_9a                  ;Yes, forget the packet
  757.  
  758.         push    cx                           ;remember length and buffer address
  759.         push    es
  760.         push    di
  761.  
  762.         mov     si,RCVPAGE*512               ;sid and did of the last fragment
  763.         mov     ds,mem_base
  764.         assume  ds:nothing
  765.         lodsw
  766.         push    cx
  767.         push    ax
  768.         mov     bx,cs
  769.         mov     ds,bx
  770.         assume  ds:code
  771.  
  772.         cmp     ah,0                            ;receiving broadcast
  773.         jne     recv_directed
  774.         mov     cx,3
  775.         mov     ax,0ffffh
  776.         rep     stosw
  777.         jmp     short recv_source
  778. recv_directed:                                  ;directed packets
  779.         xor     ax,ax
  780.         mov     cx,2
  781.         rep     stosw
  782.         pop     ax
  783.         push    ax
  784.         xor     al,al
  785.         stosw
  786. recv_source:                                    ;source address
  787.         xor     ax,ax
  788.         mov     cx,2
  789.         rep     stosw
  790.         pop     ax
  791.         mov     ah,al
  792.         xor     al,al
  793.         stosw
  794.         mov     ax,recv_protocol                ;Ethernet protocol
  795.         stosw
  796.  
  797.         mov     si,offset recv_buffer           ;with ARP and RARP its
  798.         cmp     recv_protocol,0608h             ;its just the opposite as in
  799.         je      recv_arp                        ;case of sending packets
  800.         cmp     recv_protocol,3580h
  801.         je      recv_arp
  802.         pop     cx
  803.         sub     cx,14
  804.         sub     cx,last_length
  805.         cld
  806.         jcxz    recv_move_last
  807.         call    movemem                        ;The first fragments
  808. recv_move_last:
  809.         mov     cx,last_length
  810.         mov     si,recv_packet
  811.         mov     ds,mem_base
  812.         assume  ds:nothing
  813.         cld
  814.         call    movemem                        ;And the last fragment
  815.         jmp     recv_copied
  816. recv_arp:
  817.         pop     cx
  818.         mov     si,recv_packet
  819.         mov     ds,mem_base
  820.         assume  ds:nothing
  821.         cld
  822.         xor     al,al
  823.         mov     ah,1
  824.         stosw                         ;Put Hardware-Type EtherNet at ist place
  825.         mov     ax,0008h
  826.         stosw                         ;Protocol used is IP
  827.         mov     ax,0406h              ;Length of Ethernet and IP-Adress
  828.         stosw
  829.                                       ;now we transfer ARCnet-Client-Data to Ethernet-Client-Data
  830.         add     si,6
  831.         movsw                         ;move opcode
  832.         mov     cx,5
  833.         xor     al,al                 ;Padd first five byte of source address with zero
  834.         rep     stosb
  835.         movsb                         ;Move ARCNet-Hardware Adress
  836.         movsw                         ;Sender IP-Adress
  837.         movsw
  838.         lodsb                         ;now we check destination for Broadcast
  839.         cmp     al,0
  840.         je      recv_hw_bcast
  841.         mov     ah,al                 ;directed ARP
  842.         xor     al,al
  843.         mov     cx,5
  844.         rep     stosb
  845.         mov     al,ah
  846.         stosb
  847.         jmp     recv_client_2
  848. recv_hw_bcast:
  849.         mov    ax,0ffffh              ;Target was Broadcast
  850.         mov    cx,3
  851.         rep    stosw
  852. recv_client_2:
  853.         movsw                         ;Target IP-Address
  854.         movsw
  855. recv_copied:
  856.         cmp     cs:recv_protocol,0ffffh  ;Novell 802.3 packet ?
  857.         jne     recv_copied_2
  858.  
  859.         pop     di                    ;Yes: put length in prot field
  860.         push    di
  861.     mov    ax,es:[di+16]       ; get len
  862.     xchg    ah,al
  863.     inc    ax            ; make even (rounding up)
  864.     and    al,0feh
  865.     xchg    ah,al
  866.     mov    es:[di+12],ax       ; save in prot field
  867.  
  868. recv_copied_2:
  869.  
  870.         pop     si
  871.         pop     ds
  872.         pop     cx
  873.         assume  ds:nothing
  874.         call    recv_copy               ;tell the client that we
  875.         mov     ax,cs                   ;copied the packet
  876.         mov     ds,ax
  877.         assume  ds:code
  878.         jmp     recv_isr_9
  879.  
  880.     public    recv_exiting
  881. recv_exiting:
  882. ;called from the recv isr after interrupts have been acknowledged.
  883. ;Only ds and ax have been saved.
  884.     assume    ds:nothing
  885.     ret
  886.  
  887.  
  888. end_resident    label    byte
  889.  
  890.     public    usage_msg
  891. usage_msg    db    "usage: arcether [-n] [-d] [-w] <packet_int_no> <int_no> <io_addr> <mem_base>",CR,LF,'$'
  892.  
  893.     public    copyright_msg
  894. copyright_msg    db    "Packet driver for Novell ARCnet TCP/IP and IPX version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  895.         db    "Portions Copyright 1988 Philip Prindeville",CR,LF
  896.                 db      "Copyright 1991 Martin Wilmes",CR,LF,'$'
  897.  
  898. no_arcnet_msg    db    "No ARCnet found at that address.",CR,LF,'$'
  899. failed_test_msg    db    "Failed self test.",CR,LF,'$'
  900.  
  901. int_no_name    db    "Interrupt number ",'$'
  902. io_addr_name    db    "I/O port ",'$'
  903. mem_base_name    db    "Memory address ",'$'
  904.  
  905.     extrn    set_recv_isr: near
  906.  
  907. ;enter with si -> argument string, di -> word to store.
  908. ;if there is no number, don't change the number.
  909.     extrn    get_number: near
  910.  
  911. ;enter with dx -> name of word, di -> dword to print.
  912.     extrn    print_number: near
  913.         extrn   flagbyte
  914.  
  915.     public    parse_args
  916. parse_args:
  917. ;exit with nc if all went well, cy otherwise.
  918.         test    cs:flagbyte,N_OPTION            ;Check if -n Option was used
  919.         jz      next_arg
  920.         xor     cs:flagbyte,N_OPTION            ;if yes: clear this flag and
  921.         or      OPTION_8023,N_OPTION            ;set our own flag, because
  922.         mov     cs:[driver_class+1],11          ;standard N_OPTION does not
  923.                                                 ;work with a ARCnet-Driver
  924.                                                 ;and has another meaning for us
  925. next_arg:
  926.     mov    di,offset int_no
  927.                                                 
  928.                                                 
  929.     call    get_number
  930.     mov    di,offset io_addr
  931.     call    get_number
  932.     mov    di,offset mem_base
  933.     call    get_number
  934.     clc
  935.     ret
  936.  
  937.  
  938. no_arcnet_error:
  939.     mov    dx,offset no_arcnet_msg
  940.     mov    ah,9
  941.     int    21h
  942.     jmp    short error
  943. failed_test_error:
  944.     mov    dx,offset failed_test_msg
  945.     mov    ah,9
  946.     int    21h
  947. error:
  948.     stc
  949.     ret
  950.  
  951.  
  952.     public    etopen
  953. etopen:
  954. ;reset the board via the I/O reset port, then wait for it to become sane again.
  955.  
  956.     mov    ax,mem_base        ;test the memory first.
  957.     mov    cx,2048
  958.     call    memory_test
  959.     jne    no_arcnet_error
  960.  
  961.     mov    es,mem_base
  962.  
  963.     loadport
  964.     setport SW_RST
  965.     in    al,dx
  966.  
  967.     mov    ax,RST_IVAL
  968.     call    set_timeout
  969. etopen_1:
  970.     call    do_timeout
  971.     jne    etopen_1
  972.  
  973.         loadport
  974.     setport    STATUS
  975.     in    al,dx
  976.  
  977. ;since we've just reset:
  978. ;    reset the POR flag,
  979. ;    check the diagnostic byte in the buffer,
  980. ;    grab the node ID, and assign it to the host number.
  981.  
  982.     test    al,ST_POR
  983.     je    etopen_2
  984.  
  985.         loadport
  986.     setport    COMMAND
  987.     mov    al,CLR_FLGS or FL_POR or FL_RECON
  988.     out    dx,al
  989.  
  990.     mov    al,es:[0]
  991.     cmp    byte ptr es:[0],TSTWRD
  992.     je    etopen_3
  993.     jmp    failed_test_error    ;failed power on self-test.
  994. etopen_3:
  995.     mov    al,es:[1]
  996.     mov    my_arcnet_id,al
  997. etopen_2:
  998.  
  999. ;another simple diagnostic:
  1000. ;    force test flag on in RIM,
  1001. ;    check to see that it is set,
  1002. ;    reset it.
  1003.  
  1004.     loadport
  1005.     setport    COMMAND
  1006.     mov    al,LD_TST_FLG or FL_TST
  1007.     out    dx,al
  1008.  
  1009.         loadport
  1010.     setport STATUS
  1011.     in    al,dx
  1012.  
  1013.     test    al,FL_TST
  1014.     jne    etopen_4
  1015.     jmp    failed_test_error    ;failed forced self-test.
  1016. etopen_4:
  1017.         loadport
  1018.     setport    COMMAND
  1019.     mov    al,LD_TST_FLG
  1020.     out    dx,al
  1021.         loadport
  1022.     setport STATUS
  1023.     in    al,dx
  1024.  
  1025.     pushf
  1026.     cli
  1027.  
  1028.     call    set_recv_isr
  1029.  
  1030. ;now we enable the board to interrupt
  1031. ;us on packet received.  Not transmiter available
  1032. ;(i.e. transmission complete).  We don't have
  1033. ;any control over POR, since it is NMI...
  1034. ;RECON seems useless.
  1035.  
  1036.     loadport
  1037.     setport    IMASK
  1038.     mov    al,ST_RI
  1039.     out    dx,al
  1040.  
  1041.     ; we should allow extended packets
  1042.         loadport
  1043.     setport    COMMAND
  1044.     mov    al,DFN_CONF or CONF_XTND
  1045.     out    dx,al
  1046.  
  1047.     mov    al,ENBL_RCV or (RCVPAGE shl 3) or BCAST;
  1048.     out    dx,al
  1049.  
  1050.     popf
  1051.  
  1052.     mov    al, int_no        ; Get board's interrupt vector
  1053.     add    al, 8
  1054.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1055.     jb    set_int_num        ; No.
  1056.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1057. set_int_num:
  1058.     xor    ah, ah            ; Clear high byte
  1059.     mov    int_num, ax        ; Set parameter_list int num.
  1060.  
  1061.     mov    dx,offset end_resident
  1062.     clc
  1063.     ret
  1064.  
  1065.     public    print_parameters
  1066. print_parameters:
  1067.     mov    di,offset int_no
  1068.     mov    dx,offset int_no_name
  1069.     call    print_number
  1070.     mov    di,offset io_addr
  1071.     mov    dx,offset io_addr_name
  1072.     call    print_number
  1073.     mov    di,offset mem_base
  1074.     mov    dx,offset mem_base_name
  1075.     call    print_number
  1076.     ret
  1077.  
  1078.     include    memtest.asm
  1079.  
  1080. code    ends
  1081.  
  1082.     end
  1083.